#include "fz_sticky_bag_echo_server.h"
#include "../log.h"
#include <cstdint>
#include <iomanip>

void Session::Start()
{
    m_recv_head_node->Clear();
    boost::asio::async_read(m_socket, boost::asio::buffer(m_recv_head_node->m_data.get(), HEAD_LENGTH),
    [this, ptr = shared_from_this()](const boost::system::error_code& ec, size_t len){
        _HadnleReadHead(ec, len, ptr);
    });
}

void Session::Send(char* msg, size_t len)
{
    bool pending = false; // 发送队列是否为空 - false: 当前发送队列为空，可以发送数据
    
    std::unique_lock<std::mutex> lock(m_send_lock);
    if(!m_send_que.empty())
    {
        pending = true;
    }
    if(m_send_que.size() > MAX_SEND_NUM)    //控制发送队列最大长度
    {
        log_error("Session::Send, send queue is full, size: {}", m_send_que.size());
        return;
    }

    m_send_que.push(std::make_shared<MsgNode>(msg, len));

    if(pending) //发送队列不为空，不需要再次调用发送回调函数
    {
        return;
    }

    auto& meg_node = m_send_que.front();
    boost::asio::async_write(m_socket, boost::asio::buffer(meg_node->m_data.get(), meg_node->m_max_len),
        bind(&Session::_HandleWrite, this, std::placeholders::_1, shared_from_this()));
}


void Session::PrintRecvData(char* data, uint32_t len)
{
    std::stringstream oss;

    for(size_t i = 0; i < len; ++i)
    {
        if(i > 0 && i % 32 == 0)    //每行显示32个字符
        {
            oss << std::endl;
        }

        //std::setw 设置输出宽度（8位二进制数可以表示2位16进制数）
        //std::setfill 设置填充字符，默认为空格
        // data[i] 是一个 char 类型（有符号8位）。
        // (uint8_t)data[i] 将其转换为无符号8位整数，以确保其值在0到255之间。
        // (int)(uint8_t)data[i] 将其进一步转换为整数类型，以便正确进行16进制显示。
        oss << std::setw(2) << std::setfill('0') << std::hex 
            << (int)(uint8_t)data[i] << " ";
    }

    log_debug("\n{}", oss.str());
}

void Session::_HadnleReadHead(const boost::system::error_code& ec, size_t len, std::shared_ptr<Session> self_ptr)
{
    if(ec)
    {
        m_server->DeleteSession(m_uuid);
        m_socket.close();
        log_error("Session::_HadnleRead error, code: {}, message: {}", ec.value(), ec.message());
        return;
    }

    if(len < HEAD_LENGTH)
    {
        log_error("Session::_HadnleRead, len < HEAD_LENGTH");
        m_socket.close();
        m_server->DeleteSession(m_uuid);
        return;
    }

    // 解析消息长度
    uint32_t msg_len = m_recv_head_node->GetHeadNum();
    log_debug("Session::_HadnleRead, msg_len: {}", msg_len);
    PrintRecvData(m_recv_head_node->m_data.get(), HEAD_LENGTH);
    if(msg_len > m_max_len || msg_len == 0)
    {
        log_error("Session::_HadnleRead, msg len error, msg_len: {}", msg_len);
        m_socket.close();
        m_server->DeleteSession(m_uuid);
        return;
    }

    m_recv_msg_node = std::make_shared<MsgNode>(msg_len);
    boost::asio::async_read(m_socket, boost::asio::buffer(m_recv_msg_node->m_data.get(), msg_len),
    [this, ptr = shared_from_this()](const boost::system::error_code& ec, size_t len){
        _HadnleReadMsg(ec, len, ptr);
    }); 
}

void Session::_HadnleReadMsg(const boost::system::error_code& ec, size_t len, std::shared_ptr<Session> self_ptr)
{
    if(ec)
    {
        m_server->DeleteSession(m_uuid);
        m_socket.close();
        log_error("Session::_HadnleRead error, code: {}, message: {}", ec.value(), ec.message());
        return;
    }

    if(len != m_recv_head_node->GetHeadNum())
    {
        m_server->DeleteSession(m_uuid);
        m_socket.close();
        log_error("Session::_HadnleRead error, code: {}, message: {}", ec.value(), ec.message());
        return;
    }

    log_info("Session::_HadnleRead, recv msg: {}", m_recv_msg_node->m_data.get());
    PrintRecvData(m_recv_msg_node->m_data.get(), len);

    Send(m_recv_msg_node->m_data.get(), len);
    m_recv_head_node->Clear();
    m_recv_msg_node.reset();

    boost::asio::async_read(m_socket, boost::asio::buffer(m_recv_head_node->m_data.get(), HEAD_LENGTH),
    [this, ptr = shared_from_this()](const boost::system::error_code& ec, size_t len){
        _HadnleReadHead(ec, len, ptr);
    });
}

void Session::_HandleWrite(const boost::system::error_code& ec, std::shared_ptr<Session> self_ptr)
{
    if(ec)
    {
        m_server->DeleteSession(m_uuid);
        log_error("Session::_HandleWrite error, code: {}, message: {}", ec.value(), ec.message());
        return;
    }

    std::unique_lock<std::mutex> lock(m_send_lock);
    m_send_que.pop();
    if(m_send_que.empty())
    {
        return;
    }
    auto msg = m_send_que.front();

    boost::asio::async_write(m_socket, boost::asio::buffer(msg->m_data.get(), msg->m_max_len),
        bind(&Session::_HandleWrite, this, std::placeholders::_1, shared_from_this()));
}

//=============================================================================================================================

Server::Server(boost::asio::io_context&ioc, uint16_t port)
:m_ioc(ioc)
,m_acceptor(ioc, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port))
{
    _StartAccetp();
    log_debug("server start listening on port: {}", port);
}
void Server::DeleteSession(const std::string& uuid)
{
    std::unique_lock<std::mutex> lock(m_mutex);
    auto it = m_sessions.find(uuid);
    if(it == m_sessions.end())
    {
        return;
    }
    m_sessions.erase(it);
}

//使用智能指针解决程序崩溃问题
void Server::_StartAccetp()
{
    auto session = std::make_shared<Session>(m_ioc, this);
    m_acceptor.async_accept(session->GetSocket(), 
    [this, session](const boost::system::error_code& ec){
        _HandleAccept(session, ec);
    });
}
void Server::_HandleAccept(std::shared_ptr<Session> session, const boost::system::error_code& ec)
{
    if(ec)
    {
        log_error("Server::_HandleAccept error, code: {}, message: {}", ec.value(), ec.message());
        return;
    }

    {
        std::unique_lock<std::mutex> lock(m_mutex);
        m_sessions.insert(std::make_pair(session->GetUuid(), session));
    }
    session->Start();
    _StartAccetp();
}